package so.sao.code.service.service.impl;

import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import so.sao.accessories.dto.request.PackDataInfoRequest;
import so.sao.accessories.dto.response.PackDataInfoResponse;
import so.sao.accessories.feign.client.PackDataInfoClient;
import so.sao.code.dto.request.TagScrapRequest;
import so.sao.code.dto.response.TagStatusInfoDto;
import so.sao.code.service.domain.entity.RangeActivation;
import so.sao.code.service.domain.entity.TagBatch;
import so.sao.code.service.domain.entity.TagBatchConfig;
import so.sao.code.service.domain.entity.TagScrap;
import so.sao.code.service.infrastructure.SessionContext;
import so.sao.code.service.infrastructure.dozer.Mapper;
import so.sao.code.service.infrastructure.enums.CodeMessage;
import so.sao.code.service.infrastructure.enums.TAG_SCRAP_TYPE;
import so.sao.code.service.infrastructure.model.vo.PackageCodeInfoVO;
import so.sao.code.service.infrastructure.model.vo.SingleCodeInfoVO;
import so.sao.code.service.repository.RangeActivationDao;
import so.sao.code.service.repository.TagBatchConfigDao;
import so.sao.code.service.repository.TagBatchDao;
import so.sao.code.service.repository.TagScrapDao;
import so.sao.code.service.service.TagScrapService;
import so.sao.code.service.service.TagStatusInfoService;
import so.sao.data.dto.response.EnterpriseDTO;
import so.sao.data.dto.response.FactoryDTO;
import so.sao.data.dto.response.ProductDTO;
import so.sao.data.feign.client.EnterpriseClient;
import so.sao.data.feign.client.FactoryClient;
import so.sao.data.feign.client.ProductClient;
import so.sao.ffw.dto.message.TagRangeActivationMessage;
import so.sao.ffw.feign.client.TagRangeActivationClient;
import so.sao.nosql.datastore.enums.tag.TagStatus;
import so.sao.sso.common.CommonConstants;
import so.sao.top.core.util.rest.RestException;

@Service
public class TagScrapServiceImpl implements TagScrapService {
	@Autowired
	TagScrapDao tagScrapDao;
	@Autowired
	TagBatchDao tagBatchDao;
	@Autowired
	TagBatchConfigDao tagBatchConfigDao;
	@Autowired
	RangeActivationDao rangeActivationDao;
	@Autowired
	TagStatusInfoService tagStatusInfoService;
	@Autowired
	SessionContext context;
	@Autowired
	EnterpriseClient enterpriseClient;
	@Autowired
	FactoryClient factoryClient;
	@Autowired
	ProductClient productClient;
	@Autowired
	PackDataInfoClient packDataInfoClient;
	@Autowired
	TagRangeActivationClient tagRangeActivationClient;

	@Transactional
	@Override
	public void handle(TagScrapRequest tagScrapRequest) throws Exception {
		TagScrap tagScrap = Mapper.map(tagScrapRequest, TagScrap.class);
		TagBatch tagBatch = null;
		TAG_SCRAP_TYPE type = TAG_SCRAP_TYPE.fromValue(tagScrapRequest.getTagScrapType());
		tagScrap.setType(type);
		switch (type) {
		case SCRAPBYBATCH:
			if (tagScrap.getTagBatchId() != null && !tagScrap.getTagBatchId().equals(0L)) {
				tagBatch = tagBatchDao.findOne(tagScrap.getTagBatchId());
				if (tagBatch != null)
					tagScrap.setTagScrapCount(tagBatch.getSeqnumEnd() - tagBatch.getSeqnumStart() + 1);
				tagScrap.setSeqnumStart(tagBatch.getSeqnumStart());
				tagScrap.setSeqnumEnd(tagBatch.getSeqnumEnd());
			} else {
				throw new RestException(HttpStatus.BAD_REQUEST, CodeMessage.InvalidRequest);
			}
			scrapTag(tagBatch, tagScrap);
			break;
		case SCRAPBYCODESEGMENT:
			if (tagScrap.getSeqnumStart() != null && tagScrap.getSeqnumEnd() != null) {
				TagBatch tagBatchStart = tagBatchDao.getTagBatchBySeqNum(tagScrap.getSeqnumStart());
				tagBatch = tagBatchDao.getTagBatchBySeqNum(tagScrap.getSeqnumEnd());
				if (tagBatchStart != null && tagBatch != null && tagBatchStart.getId().equals(tagBatch.getId())) {
					tagScrap.setTagScrapCount(tagScrap.getSeqnumEnd() - tagScrap.getSeqnumStart() + 1);
				} else {
					throw new RestException(HttpStatus.BAD_REQUEST, CodeMessage.InvalidRequest);
				}
			} else {
				throw new RestException(HttpStatus.BAD_REQUEST, CodeMessage.InvalidRequest);
			}
			scrapTag(tagBatch, tagScrap);
			break;
		case SCRAPBYCODE:
			tagBatch = tagBatchDao.getTagBatchBySeqNum(tagScrap.getSeqnum());
			tagScrap.setSeqnumStart(tagScrap.getSeqnum());
			tagScrap.setSeqnumEnd(tagScrap.getSeqnum());
			tagScrap.setTagScrapCount(1L);
			scrapTag(tagBatch, tagScrap);
			break;
		case SCRAPBYBOX:
			Long seqNum = tagScrap.getSeqnum();
			PackDataInfoRequest packDataInfoRequest = new PackDataInfoRequest();
			packDataInfoRequest.setTagNoUrl(String.valueOf(seqNum));
			ResponseEntity<PackDataInfoResponse> res = packDataInfoClient.getPackDataInfo(packDataInfoRequest);
			tagScrap.setTagScrapCount(res.getBody().getTotalTagCount());
			tagScrap.setPrintFactoryName(res.getBody().getProdFactoryName());
			tagScrap.setPrintFactoryId(res.getBody().getProdFactoryId());
			tagScrap.setTerminalId(res.getBody().getTerminalId());
			tagBatch = tagBatchDao.getTagBatchBySeqNum(seqNum);
			tagScrap.setSeqnumStart(seqNum);
			tagScrap.setSeqnumEnd(seqNum);
			scrapTag(tagBatch, tagScrap);
			break;
		default:
			throw new IllegalArgumentException("Value [" + tagScrap.getType() + "] not support!");
		}

	}

	private void scrapTag(TagBatch tagBatch, TagScrap tagScrap) throws Exception {
		if (tagBatch != null) {
			TagBatchConfig tagBatchConfig = tagBatchConfigDao.findByTagBatchId(tagBatch.getId());
			if (tagBatchConfig != null) {
				tagScrap.setUserName(context.CURRECT_USER.getUsername());
				tagScrap.setTagBatchName(tagBatch.getName());
				tagScrap.setEseId(tagBatch.getEseId());
				EnterpriseDTO enterpriseDto = enterpriseClient.findById(tagBatch.getEseId());
				tagScrap.setEnterpriseName(enterpriseDto.getName());
				List<RangeActivation> rangeActivationList = rangeActivationDao
						.findByTagBatchId(tagScrap.getTagBatchId());
				if (rangeActivationList.size() > 0) {
					RangeActivation rangeActivation = rangeActivationList.stream().findFirst().get();
					tagScrap.setProductId(rangeActivation.getProductId());
					Optional<ProductDTO> product = Optional
							.ofNullable(productClient.findById(rangeActivation.getProductId()));
					if (product.isPresent()) {
						tagScrap.setProductName(product.get().getName());
					}
				}
				if (tagScrap.getType().getValue() == TAG_SCRAP_TYPE.SCRAPBYCODE.getValue()
						|| tagScrap.getType().getValue() == TAG_SCRAP_TYPE.SCRAPBYBOX.getValue()) {
					TagStatusInfoDto res = tagStatusInfoService.getTagStatusInfoBy(tagScrap.getSeqnum().toString(),
							true);
					tagScrap.setProductId(res.getProductId());
					Optional<ProductDTO> product = Optional.ofNullable(productClient.findById(res.getProductId()));
					if (product.isPresent()) {
						tagScrap.setProductName(product.get().getName());
					}
				}
				if (tagScrap.getType().getValue() != TAG_SCRAP_TYPE.SCRAPBYBOX.getValue()
						&& tagBatchConfig.getPrintFactoryId() != null
						&& !tagBatchConfig.getPrintFactoryId().equals(0L)) {
					Optional<FactoryDTO> factory = Optional
							.ofNullable(factoryClient.findById(tagBatchConfig.getPrintFactoryId()));
					tagScrap.setPrintFactoryId(tagBatchConfig.getPrintFactoryId());
					tagScrap.setTerminalId(tagBatchConfig.getTerminalId().toString());
					if (factory.isPresent()) {
						tagScrap.setPrintFactoryName(factory.get().getName());
					}
				}
			} else {
				throw new RestException(HttpStatus.BAD_REQUEST, CodeMessage.NoDataConfig);
			}
		} else {
			throw new RestException(HttpStatus.BAD_REQUEST, CodeMessage.InvalidRequest);
		}
		tagScrapDao.save(tagScrap);
		TagRangeActivationMessage message = new TagRangeActivationMessage();
		message.setDomain(tagBatch.getDomain());
		message.setSeqnumStart(tagScrap.getSeqnumStart());
		message.setSeqnumEnd(tagScrap.getSeqnumEnd());
		message.setSubDomain(tagBatch.getSubDomain());
		message.setTagBatchId(tagBatch.getId());
		message.setStatus(TagStatus.INVALID.getStatus());
		tagRangeActivationClient.tagRangeActivationMessageToQueue(message);
	}

	@Override
	public Page<TagScrap> getTagScrapList(Specification<TagScrap> spec, Pageable pageable) {
		return tagScrapDao.findAll(spec, pageable);
	}

	@Override
	public PackageCodeInfoVO findPackageCodeInfo(String packageUrlOrSerialNumber) throws Exception {
		PackageCodeInfoVO packageCodeInfo = new PackageCodeInfoVO();
		long seqNum = tagStatusInfoService.getTagSeqNum(packageUrlOrSerialNumber);
		if (seqNum > 0) {
			Optional<TagBatch> result = Optional.ofNullable(tagBatchDao.getTagBatchBySeqNum(seqNum));
			if (result.isPresent()) {
				if (!result.get().getEseId().equals(context.CURRECT_USER.getEseId())
						&& !context.CURRECT_USER.getEseId().equals(1L)) {
					return packageCodeInfo;
				}
				PackDataInfoRequest packDataInfoRequest = new PackDataInfoRequest();
				packDataInfoRequest.setTagNoUrl(String.valueOf(seqNum));
				ResponseEntity<PackDataInfoResponse> res = packDataInfoClient.getPackDataInfo(packDataInfoRequest);
				if(res.getBody().getCode()==null){
				packageCodeInfo = Mapper.map(res.getBody(), PackageCodeInfoVO.class);
					Optional<TagScrap> tagScrap = Optional
							.ofNullable(tagScrapDao.findBySeqnum(Long.valueOf(packageCodeInfo.getPackNo())));
					if (tagScrap.isPresent()) {
						packageCodeInfo.setScrapStatus(1);
					}
				}
			}
		}
		return packageCodeInfo;
	}

	@Override
	public SingleCodeInfoVO findSingleCodeInfo(String codeUrlOrEncryptionStr) throws Exception {
		TagStatusInfoDto res = tagStatusInfoService.getTagStatusInfoBy(codeUrlOrEncryptionStr, true);
		SingleCodeInfoVO singleCodeInfoVO = new SingleCodeInfoVO();
		if (res.getCode()== null) {
			if (!res.getEseId().equals(context.CURRECT_USER.getEseId())
					&& !context.CURRECT_USER.getEseId().equals(1L)) {
				return singleCodeInfoVO;
			}
			singleCodeInfoVO = Mapper.map(res, SingleCodeInfoVO.class);
			singleCodeInfoVO.setSeqNum(res.getSeqNum().toString());
			singleCodeInfoVO.setTagUrl(res.getDomain() + "/" + res.getSubDomain() + "/" + res.getCodes().get(0));
			Optional<ProductDTO> product = Optional.ofNullable(productClient.findById(res.getProductId()));
			if (product.isPresent()) {
				singleCodeInfoVO.setProductName(product.get().getName());
			}
			if (res != null) {
				Optional<TagScrap> tagScrap = Optional.ofNullable(tagScrapDao.getScrapInfoBySeqnum(res.getSeqNum()));
				if (tagScrap.isPresent()) {
					singleCodeInfoVO.setScrapStatus(1);
				} else {
					PackDataInfoRequest packDataInfoRequest = new PackDataInfoRequest();
					packDataInfoRequest.setTagNoUrl(String.valueOf(res.getSeqNum()));
					PackDataInfoResponse packDataInfo = packDataInfoClient.getPackDataInfo(packDataInfoRequest)
							.getBody();
					if (packDataInfo.getPackNo() != null) {
						Optional<TagScrap> tagScrap1 = Optional
								.ofNullable(tagScrapDao.getScrapInfoBySeqnum(Long.valueOf(packDataInfo.getPackNo())));
						if (tagScrap1.isPresent()) {
							singleCodeInfoVO.setScrapStatus(1);
						}
					}
				}
			}
		}
		
		return singleCodeInfoVO;
	}

	@Override
	public Boolean getTagScrapResult(Long seqNum) {
		Optional<TagScrap> tagScrap = Optional.ofNullable(tagScrapDao.getScrapInfoBySeqnum(seqNum));
		if (tagScrap.isPresent()) {
			return true;
		}
		return false;
	}

	@Override
	public List<TagScrap> findTagScrapInfoByScrapType(TAG_SCRAP_TYPE type) {
		return tagScrapDao.findByType(type);
	}
}
